package com.dimao.certificate_build_service.pdf.kotiln

import com.itextpdf.kernel.pdf.PdfDocument
import com.itextpdf.kernel.pdf.PdfReader
import com.itextpdf.kernel.pdf.PdfWriter
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.kotlin.coroutines.awaitResult
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException

class PDFMerge {
    companion object {
        suspend fun merge(vertx: Vertx, pdfFileNames: List<String>): Buffer = coroutineScope {
            val pdfFutures = ArrayList<Deferred<Unit>>(pdfFileNames.size)
            val outputStream = ByteArrayOutputStream()
            var pdfDocument: PdfDocument? = null

            try {
                pdfDocument = awaitResult { h ->
                    vertx.executeBlocking<PdfDocument>(Handler { promise ->
                        try {
                            val document = PdfDocument(PdfWriter(outputStream))
                            promise.complete(document)
                        } catch (e: IOException){
                            promise.fail(e)
                        }
                    }, h)
                }

                for(pdfFileName in pdfFileNames){
                    pdfFutures.add(async {
                        val buffer = awaitResult<Buffer> { h -> vertx.fileSystem().readFile(pdfFileName, h) }
                        awaitResult<Unit> { h ->
                            vertx.executeBlocking<Unit>(Handler { promise ->
                                var inputStream: ByteArrayInputStream? = null
                                var mergeInPdfDocument: PdfDocument? = null

                                try {
                                    inputStream = ByteArrayInputStream(buffer.bytes)
                                    mergeInPdfDocument = PdfDocument(PdfReader(inputStream))
                                    mergeInPdfDocument.copyPagesTo(listOf(1), pdfDocument)
                                } catch (e: IOException){
                                    promise.fail(e)
                                } finally {
                                    mergeInPdfDocument?.close()
                                    inputStream?.close()
                                }

                                promise.complete(Unit)
                            }, h)
                        }
                    })
                }

                pdfFutures.forEach { future -> future.await() }
            } finally {
                awaitResult<Unit> { h ->
                    vertx.executeBlocking<Unit>(Handler { promise ->
                        pdfDocument?.close()
                        outputStream.close()
                        promise.complete(Unit)
                    }, h)
                }
            }

            return@coroutineScope Buffer.buffer(outputStream.toByteArray())
        }
    }
}